package com.util;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.ibatis.annotations.Mapper;
import org.codehaus.jackson.map.ObjectMapper;

import javax.imageio.ImageIO;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

//@WebServlet(name = "DispathServlet",value = "/",loadOnStartup = 1)
@MultipartConfig    //传输文件流
public class DispathServlet extends HttpServlet {
    //映射目录集合
    private Map<String, Mapper> mapperMap = new HashMap<>();

    /**
     * 初始化
     *
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        //获取配置参数
        String packageName = config.getInitParameter("packageName");
        if (packageName == null || "".equals(packageName)) {
            packageName = "com.controller";
        }
        //ScanUtil 扫描工具,获取指定包下有指定注解的类的集合
        Set<Class> classes = ScanUtil.scanPackage4AnnotatedClass(packageName, Controller.class);
        try {
            //遍历集合,创建映射目录
            for (Class clazz : classes) {
                //newInstance()实例化对象
                Object servletObject = clazz.getDeclaredConstructor().newInstance();
                //getMethods()获取类的方法集合
                Method[] methods = clazz.getMethods();
                //遍历方法集合
                for (Method method : methods) {
                    //getAnnotation()获取方法上指定的注解
                    RequestMapping annotation = method.getAnnotation(RequestMapping.class);
                    //判断该注解是否存在
                    if (annotation != null) {
                        //获取注解中的url
                        String value = annotation.value();
                        //将url与对象和方法绑定; Mapper:自定义的内部类
                        mapperMap.put(value, new Mapper(servletObject, method));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //打印目录
        mapperMap.forEach((k, v) -> {
            System.out.println(k);
        });
    }

    /**
     * 请求分发核心
     *
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        //获取用户的请求
        String servletPath = request.getServletPath();
//        System.out.println("这是我的DispathServlet.service()  servlet=" + servletPath);
//request.getRequestDispatcher("WEB-INF/html/index.html").forward(request,response);
        //检查用户的请求是否存在
        if (mapperMap.containsKey(servletPath)) {
            try {
                //调用controller方法
                Object result = mapperMap.get(servletPath).invoke(request, response);
                /**"index" :  跳转到index.html
                 "forward:XXXXX" : 跳转到某个controller方法
                 "forward:/XX/XX/XXXXX.html" : 跳转到某个路径下的页面
                 "redirect:XXXXX": 重定向到某个controller方法
                 "redirect:/XXX/XXX/XXXXX.html": 重定向到某个路径下的页面*/
                //判断
                if (result instanceof String) {
                    //将返回的结果转型为字符串
                    String resultStr = result.toString();
                    System.out.println("resultStr:"+resultStr);
                    //判断字符串是以forward开头还是redirect开头
                    if (resultStr.startsWith("forward:")) {
                        resultStr = resultStr.substring(8);
                        request.getRequestDispatcher(resultStr).forward(request, response);
                    } else if (resultStr.startsWith("redirect:")) {
                        resultStr = resultStr.substring(9);
                        response.sendRedirect(resultStr);
                    } else if(resultStr.startsWith("text:")){
                        System.out.println("abcd:3");
                        resultStr = resultStr.substring(5);
                        response.getWriter().write(resultStr);
                    }else{
                        System.out.println("abcd:4");
                        //ajax直接返回文本消息
                        response.getWriter().write("html/"+resultStr+".html");
                    }
                    //返回对象是一个图片缓存
                } else if (result instanceof BufferedImage) {
                    //转型
                    BufferedImage imgBuff = (BufferedImage) result;
                    //设置响应包的参数
                    response.setDateHeader("Expires", 0);
                    //禁用缓存,浏览器每次都要请求服务器,服务器每次都要返回200状态码以及资源内容
                    response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
                    // Set IE extended HTTP/1.1 no-cache headers (use addHeader).
                    response.addHeader("Cache-Control", "post-check=0, pre-check=0");
                    // 要求所有的中间服务器不返回缓存的资源。是http/1.1之前版本的历史遗留字段，仅作为与http的向后兼容而定义。
                    response.setHeader("Pragma", "no-cache");
                    // 返回jpeg图片
                    response.setContentType("image/jpeg");

                    // 获取response的输出流
                    ServletOutputStream out = response.getOutputStream();
                    // ImageIO工具输出图片
                    ImageIO.write(imgBuff, "jpg", out);
                } else {
                    //如果不是字符串对象就按ajax的返回处理
                    //将返回对象转换为JSON字符串
                    ObjectMapper om = new ObjectMapper();
                    String resultJSON = om.writeValueAsString(result);

                    //ajax直接返回文本信息
                    response.getWriter().write(resultJSON);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            //如果请求是 / 则渲染index首页
            if (servletPath.equals("/")) {
                request.setAttribute("forward", "index");
            }
        }
    }

    @Data
    @AllArgsConstructor
    class Mapper {
        Object servletObj;
        Method method;

        //映射:反射调用
        public Object invoke(Object... args) throws InvocationTargetException, IllegalAccessException {
            return method.invoke(servletObj, args);
        }
    }
}

